package cn.gwm.flink.streaming.strategy.vehiclepredict;

import cn.gwm.flink.streaming.constant.ChargePredictFields;
import cn.gwm.flink.streaming.strategy.multidimension.MultiDimensionTimePredict;
import cn.gwm.flink.streaming.task.ChargePredictDwsTask;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.common.state.ReadOnlyBroadcastState;
import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
import org.apache.flink.api.java.typeutils.MapTypeInfo;
import org.apache.flink.streaming.api.functions.co.KeyedBroadcastProcessFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisCluster;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author : GW00280745
 * @date : 2022/5/11 16:05
 * @description :末端温度预估需求描述
 * 1.信号获取
 * 内部最大SOC、电池最高温度、电池最低温度、电池平均温度、电流值、时间值、终止SOC值(Tbox_BattSOCLim)、SOH
 * 2.流程
 * 1)	初值点
 *      根据当前电流、温度、soc进行一次[预估]
 * 2)	间隔点计算
 *  将SOC从初值点增加1%(TBD)作为SOC间隔点
 *  每个间隔点进行一次[预估]
 * 3)	预估间隔点充电温度
 *  获取计算所需信号：电流、温度、soc(内部最大SOC值)、HUT设定的终止SOC值
 *  预估步骤：
 *      公式 T_k'＝T_k+S_k*△t
 *          说明：S_k为温升速率，△t为充入1%电量的充电时间
 *      A. SOC + 温度 获取平均电流 I_k
 *      B. I_k + 温度 获取温升速率 S_k
 *      C. delta_time = (Cap*SOH_k*1%)/I_k
 *          说明：Cap_额定为电池的额定容量，I_k为充电电流，SOH_k为车端上传、鉴别后的电池包健康状态
 *      D. 带入公式计算当前soc的预估温度
 *      E. 遇到终止SOC值停止
 */
public class SocInterval implements Serializable {
    private static Logger logger = LoggerFactory.getLogger(SocInterval.class);
    private MapStateDescriptor<String, Map<String, Object>> confInfo = new MapStateDescriptor<>("conf-info", BasicTypeInfo.STRING_TYPE_INFO, new MapTypeInfo<>(String.class, Object.class));
    private String redisNameSpaceTemp;
    private String redisNameSpaceBatter;
    private JSONObject defaultDcBatterMap;
    private SocMapDefault socMapDefault;
    private MultiDimensionTimePredict timePredict = new MultiDimensionTimePredict();
    private OneSocCal oneSocCal = new OneSocCal();
    public SocInterval(String redisNameSpaceTemp1, String redisNameSpaceBatter1, JSONObject defaultBatterMap, SocMapDefault socMapDefault){
        this.redisNameSpaceTemp = redisNameSpaceTemp1;
        this.redisNameSpaceBatter = redisNameSpaceBatter1;
        this.defaultDcBatterMap = defaultBatterMap;
        this.socMapDefault = socMapDefault;
    }

    public void process(JSONObject line,
                        MapState<String, String> latestSocIntervalPointState,
                        MapState<String, String> latestEstimateState,
                        MapState<String, String> latestBatterState,
                        KeyedBroadcastProcessFunction.ReadOnlyContext ctx,
                        MapState<String, Map> mapTempAvgState,
                        JedisCluster socIntervalJedis,
                        MapState<String, String> oneSocTimeState
                        ){
        try {
            intervalPoint(line,latestSocIntervalPointState,latestEstimateState,latestBatterState,ctx,mapTempAvgState,socIntervalJedis,oneSocTimeState);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    private void intervalPoint(JSONObject line,
                               MapState<String, String> latestSocIntervalPointState,
                               MapState<String, String> latestEstimateState,
                               MapState<String, String> latestBatterState,
                               KeyedBroadcastProcessFunction.ReadOnlyContext ctx,
                               MapState<String, Map> mapTempAvgState,
                               JedisCluster socIntervalJedis,
                               MapState<String, String> oneSocTimeState
                        ) throws Exception{
        String frVal = line.getString(ChargePredictFields.ins().frField);
        line.put("flag","default");
        //首条记录是空值情况下
        if (StringUtils.isBlank(frVal) && ChargePredictDwsTask.predict_type==1){
            line.put(ChargePredictFields.ins().stdFieldSocIntervalPoint,ChargePredictFields.ins().zeroStr);
            return;
        }
        String chargeGroupName = line.getString(ChargePredictFields.ins().dwsFieldChargeBegin);
        BigDecimal socValue = line.getBigDecimal(ChargePredictFields.ins().srcFieldBmsSoc);
        Long tidValue = line.getLong(ChargePredictFields.ins().srcFieldTid);
        String stsValue = tidValue.toString().concat(ChargePredictFields.ins().char3).concat(socValue.toString());
        //有首条记录，那么判断状态中是否有数据，如果没有那么首条记录就是第一个间隔点
        if (!latestSocIntervalPointState.contains(chargeGroupName)){
            //间隔点标识为1
            line.put(ChargePredictFields.ins().stdFieldSocIntervalPoint,ChargePredictFields.ins().oneStr);
            //根据间隔点统计的中蕴含的信息回填到数据中
            if (ChargePredictDwsTask.predict_type==DwsStrConstant.ins().num1){
                tempEstimate2Line(line,ctx,latestEstimateState,latestBatterState,mapTempAvgState,socIntervalJedis);
            }else if (ChargePredictDwsTask.predict_type==DwsStrConstant.ins().num2){
                timePredict.timeV1(latestEstimateState, line, chargeGroupName, socIntervalJedis,true);
                System.out.println(line.toJSONString());
            }
            //更新状态
            latestSocIntervalPointState.put(chargeGroupName,stsValue);
            //当前充电的第一次预测
            line.put(ChargePredictFields.ins().stdFieldEstiFirstPoint,ChargePredictFields.ins().oneStr);
            //标识这个预测值是计算出的不是复制的值 为了区分间隔点 选择不同的值作为区分
//            line.put(ChargePredictFields.ins().stdField_estiPoint,ChargePredictFields.ins().oneStr)
            line.put(ChargePredictFields.ins().stdFieldEstiPoint,ChargePredictFields.ins().twoStr);
            return;
        }
        //状态中有数据，那么进行间隔点条件比较
        Boolean isIntervalPoint = intervalPointCheck(chargeGroupName, socValue,ctx,latestSocIntervalPointState);
        if (!isIntervalPoint){
            //间隔点标识为0
            line.put(ChargePredictFields.ins().stdFieldSocIntervalPoint,ChargePredictFields.ins().zeroStr);
            //不是间隔点需要复制之前的预测值
            line.put(ChargePredictFields.ins().stdFieldEstimateTemp,latestEstimateState.get(ChargePredictFields.ins().stdFieldEstimateTemp));
            line.put(ChargePredictFields.ins().stdFieldEstimateTime,latestEstimateState.get(ChargePredictFields.ins().stdFieldEstimateTime));
            line.put(ChargePredictFields.ins().stdFieldPredictTime,latestEstimateState.get(ChargePredictFields.ins().stdFieldPredictTime));
            line.put(ChargePredictFields.ins().stdFieldPredictTimeV2,latestEstimateState.get(chargeGroupName));
            //标识这个预测值是复制的值不是计算出的
            line.put(ChargePredictFields.ins().stdFieldEstiPoint,ChargePredictFields.ins().zeroStr);
            return;
        }
        //符合间隔点条件 进行间隔点预算
        //间隔点标识为1
        line.put(ChargePredictFields.ins().stdFieldSocIntervalPoint,ChargePredictFields.ins().oneStr);
        //根据间隔点统计的中蕴含的信息回填到数据中
        if (ChargePredictDwsTask.predict_type==DwsStrConstant.ins().num1){
            tempEstimate2Line(line,ctx,latestEstimateState,latestBatterState,mapTempAvgState,socIntervalJedis);
        }else if (ChargePredictDwsTask.predict_type==DwsStrConstant.ins().num2){
//            timePredict.timeV1(latestEstimateState, line, chargeGroupName, socIntervalJedis,false)
            oneSocCal.process(line,oneSocTimeState,latestEstimateState);
//            System.out.println(line.toJSONString())
        }
        //标识这个预测值是计算出的不是复制的值
        line.put(ChargePredictFields.ins().stdFieldEstiPoint,ChargePredictFields.ins().oneStr);
        //更新状态
        latestSocIntervalPointState.put(chargeGroupName,stsValue);
    }
    /**
     * @description:  间隔点条件判断
     * @author:  GW00280745
     * @date: 2022/5/19 11:00
     * @param: chargeGroupName
     * @param: socValue
     * @return: java.lang.Boolean
     **/
    private Boolean intervalPointCheck(String chargeGroupName, BigDecimal socValue,
                                       KeyedBroadcastProcessFunction.ReadOnlyContext ctx,
                                       MapState<String, String> latestSocIntervalPointState) throws Exception {
        String latestStsValue = latestSocIntervalPointState.get(chargeGroupName);
        String[] sp = latestStsValue.split(ChargePredictFields.ins().char3);
        String latestTidStr = sp[0];
        BigDecimal latestSocValue = new BigDecimal(sp[1]);
//        String socStepStr = confMysql(ctx, BmsParamField.param_batterMap_socStep,"1.0")
        String socStepStr = DwsStrConstant.ins().num5fStr;
        if (ChargePredictDwsTask.predict_type == DwsStrConstant.ins().num2) {
            socStepStr = DwsStrConstant.ins().num5fStr;
        }
        BigDecimal socStep = new BigDecimal(socStepStr);
        BigDecimal socLim = latestSocValue.add(socStep);
        if (socValue.compareTo(socLim) >= 0) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * @description: 预估结果存储到line中
     * @author:  GW00280745
     * @date: 2022/5/19 10:48
     * @param: line
     * @return:
     **/
    private void tempEstimate2Line(JSONObject line,
                                   KeyedBroadcastProcessFunction<Object, JSONObject, JSONObject, JSONObject>.ReadOnlyContext ctx,
                                   MapState<String, String> latestEstimateState,
                                   MapState<String, String> latestBatterState,
                                   MapState<String, Map> mapTempAvgState,
                                   JedisCluster socIntervalJedis) throws Exception{
        List<String> intervalPointTemp = tempEstimate(line,ctx,mapTempAvgState,latestBatterState,socIntervalJedis);
        if (intervalPointTemp==null || intervalPointTemp.size()==0){
            line.put(ChargePredictFields.ins().stdFieldEstimateTemp,latestEstimateState.get(ChargePredictFields.ins().stdFieldEstimateTemp));
            line.put(ChargePredictFields.ins().stdFieldEstimateTime,latestEstimateState.get(ChargePredictFields.ins().stdFieldEstimateTime));
            return;
        }
        line.put(ChargePredictFields.ins().dwsFieldEstiTempList,intervalPointTemp);
        //socVal#endTemp#time
        String endVal = intervalPointTemp.size()==0?ChargePredictFields.ins().blankStr:intervalPointTemp.get(intervalPointTemp.size() - 1);
        String[] split = endVal.split(ChargePredictFields.ins().char3);
        //预估温度字段
        line.put(ChargePredictFields.ins().stdFieldEstimateTemp,split[1]);
        latestEstimateState.put(ChargePredictFields.ins().stdFieldEstimateTemp,split[1]);
        //预估时长字段
        line.put(ChargePredictFields.ins().stdFieldEstimateTime,split[2]);
        latestEstimateState.put(ChargePredictFields.ins().stdFieldEstimateTime,split[2]);
        //predict_time字段   原本格式= 2022-09-10 17:05:22  临时用它存储每次预测的过程
        String predictTime = predictTime(line, split);
        line.put(ChargePredictFields.ins().stdFieldPredictTime,predictTime);
        latestEstimateState.put(ChargePredictFields.ins().stdFieldPredictTime,predictTime);

        line.put(ChargePredictFields.ins().stdFieldPredictTime +"_v1",endVal);
    }

    private String predictTime(JSONObject line, String[] split) {
        try {
            //预测时间单位=min
            long estiTime = new BigDecimal(split[2]).longValue();
            long l = estiTime * 60 * 1000L;
            Long tid = line.getLong(ChargePredictFields.ins().srcFieldTid);
            long ls = tid + l;
            String format = DateFormatUtils.format(ls, ChargePredictFields.ins().yyyyMmddss);
            return format;
        }catch (Exception e){
            return ChargePredictFields.ins().blankStr;
        }
    }

    /**
     * @description: 温度预估功能
     * 获取计算所需信号：电流、温度、soc(内部最大SOC值)、HUT设定的终止SOC值
     * 预估步骤：
     *  *      公式 T_k'＝T_k+S_k*△t
     *  *          说明：S_k为温升速率，△t为充入1%电量的充电时间
     *  *      A. SOC + 温度 -> 获取平均电流 I_k
     *  *      B. I_k + 温度 -> 获取温升速率 S_k
     *  *      C. delta_time = (Cap*SOH_k*1%)/I_k
     *  *          说明：Cap_额定为电池的额定容量，I_k为充电电流，SOH_k为车端上传、鉴别后的电池包健康状态
     *  *      D.带入公式计算当前soc的预估温度
     *  *      E.遇到终止SOC值停止
     * @author:  GW00280745
     * @date: 2022/5/19 10:48
     * @param: line
     * @return: java.util.List<java.lang.String>
     **/
    private List<String> tempEstimate(JSONObject line,
                                      KeyedBroadcastProcessFunction<Object, JSONObject, JSONObject, JSONObject>.ReadOnlyContext ctx,
                                      MapState<String, Map> mapTempAvgState,
                                      MapState<String,String> latestBatterState,
                                      JedisCluster jedis
    ) throws Exception{

        //1.信号获取 内部最大SOC、电池最高温度、电池最低温度、电池平均温度、电流值、时间值、终止SOC值(Tbox_BattSOCLim)、SOH
        BigDecimal socValue = null;
        if (line.containsKey(ChargePredictFields.ins().dwsFieldInnerMaxSoc)){
            socValue = line.getBigDecimal(ChargePredictFields.ins().dwsFieldInnerMaxSoc);
        }else {
            socValue = line.getBigDecimal(ChargePredictFields.ins().srcFieldBmsSoc);
        }
        BigDecimal tempValue = line.getBigDecimal(ChargePredictFields.ins().stdFieldTemp);
        BigDecimal batterValue = line.getBigDecimal(ChargePredictFields.ins().srcFieldBmsBatterCurrRm);
        String bmsCellVoltMax = line.getString(ChargePredictFields.ins().srcFieldVoltMax);
        String bmsCellVoltMin = line.getString(ChargePredictFields.ins().srcFieldVoltMin);
        ReadOnlyBroadcastState<String, Map<String, Object>> broadcastState = ctx.getBroadcastState(confInfo);
        Map<String, Object> confMap = broadcastState.get(null);
        String capacity = line.getString(ChargePredictFields.ins().srcFieldBatterCapacity);
        if (StringUtils.isBlank(capacity) || StringUtils.equalsIgnoreCase(capacity,ChargePredictFields.ins().defaultVal)){
//            capacity = parseConf(confMap, BmsParamField.param_batter_capacity,"179")
            capacity = DwsStrConstant.ins().num179Str;
        }
        BigDecimal capBd = new BigDecimal(capacity);
        Integer sohValue = line.getInteger(ChargePredictFields.ins().srcFieldBmsSoh);
        String socLim = null;
        if (line.containsKey(ChargePredictFields.ins().srcFieldSocLim)){
            socLim = line.getString(ChargePredictFields.ins().srcFieldSocLim);
        }else {
//            socLim = parseConf(confMap,"targetSoc",EndTempConstant.percent100)
            socLim = DwsStrConstant.ins().num100Str;
        }
        if (StringUtils.isBlank(socLim)
                || StringUtils.equalsIgnoreCase(socLim,ChargePredictFields.ins().defaultVal)
                || StringUtils.equalsIgnoreCase(socLim,ChargePredictFields.ins().defaultBlankVal)
        ){
            socLim=DwsStrConstant.ins().num100Str;
        }
        String vinVal = line.getString(ChargePredictFields.ins().srcFieldVin);
        BigDecimal socLimitVal = ChargeInfo.single().percentVal2Int(socLim);
        //2.温度预估
        LinkedList<String> intervalTempList = new LinkedList<>();
        if (tempValue == null){
            return null;
        }
        //每单位soc预测一次
//        String socStepStr = confMysql(ctx, BmsParamField.param_batterMap_socStep,"10")
        String socStepStr = "1";
        BigDecimal socStep = new BigDecimal(socStepStr);
        String tmpTemp = tempValue.toString();
        BigDecimal sumDeltaTime = new BigDecimal(0);
        boolean endFlag = false;
        while (true){
            if (socValue.compareTo(socLimitVal)>0){
                socValue=socLimitVal;
                endFlag=true;
            }
            //2.1 求I_k
            String axisBatter = AxisInfo.singleInstance().axisBatter(line,socValue.toString(),tmpTemp,confMap,false);
//            String axisBatter = ChargeUtil.single().axisBatter(line,socValue.toString(),tmpTemp)
            String batterRedisKey = redisNameSpaceBatter.concat(axisBatter);
//            String batterState = ChargeUtil.single().getRedisHValBatter(jedis, batterRedisKey,vinVal) //此方法是如果没有那么查找同款车型
            String batterState = null;
//            if (socValue.compareTo(new BigDecimal(94))>=0 ){
//                //soc 末端策略
//                if (156 != Double.parseDouble(capacity)){
//                    //soc快慢时电流降低，但温度不一定预测准确 导致坐标错误
//                    String axis_soc = AxisUtil.singleInstance().axis(socValue.toString(), 94, 100, 6)
//                    String redisKeySoc = redisNameSpace_batter.concat(axis_soc)
//                    batterState = jedis.hget(redisKeySoc,vinVal)
//                }else {
//                    //400
//                    String axis_soc = AxisUtil.singleInstance().axis(socValue.toString(), 94, 100, 6)
//                    String redisKeySoc = EndTempConstant.redisNameSpace_batterSoc.concat(axis_soc)
//                    String map_val_soc = jedis.hget(redisKeySoc, vinVal)
//                    if (StringUtils.isNotBlank(map_val_soc)){
//                        JSONObject jsonObject = JSONObject.parseObject(map_val_soc)
//                        BigDecimal avg = jsonObject.getBigDecimal("avg")
//                        BigDecimal multiply = avg.multiply(new BigDecimal(capacity))
//                        JSONObject jsonObject1 = new JSONObject()
//                        jsonObject1.put(EndTempConstant.batterMoveAvgField,multiply)
//                        batterState = jsonObject1.toJSONString()
//                    }
//                }
//            }else{
//                batterState = ChargeUtil.single().getRedisHValNoDefault(jedis, batterRedisKey,vinVal)
            batterState = RocksData.obj().getRocksValNoDefault(mapTempAvgState,batterRedisKey,vinVal);
            String iK = JSONObject.parseObject(StringUtils.isBlank(batterState)?ChargePredictFields.ins().jsonBlank:batterState).getString(ChargePredictFields.ins().batterMoveAvgField);
            if (StringUtils.isBlank(iK)){
//                //查找I_K得默认值
//                String axisBatterDefault = ChargeUtil.single().axisBatterDefaultSOC(line,socValue.toString(),tmpTemp)
//                String batterRedisKeyDefault = redisNameSpace_batter.concat(axisBatterDefault)
////                String i_kAvg = ChargeUtil.single().getRedisHValBatter(jedis, batterRedisKeyDefault, "avg")
//                String i_kAvg = ChargeUtil.single().getRedisHValNoDefault(jedis, batterRedisKeyDefault, vinVal)
//                i_k = JSONObject.parseObject(StringUtils.isBlank(i_kAvg)?EndTempConstant.jsonBlank:i_kAvg).getString(EndTempConstant.batterMoveAvgField)
//                if (StringUtils.isBlank(i_k)){
////                    //可以考虑是否用同款车型 同款车型电流变化幅度太大 例如 快充 100 和 80 ，慢充 19 和 9
////                    i_kAvg = ChargeUtil.single().getRedisHValBatter(jedis, batterRedisKeyDefault, vinVal)
////                    i_k = JSONObject.parseObject(StringUtils.isBlank(i_kAvg)?EndTempConstant.jsonBlank:i_kAvg).getString(EndTempConstant.batterMoveAvgField);
//                    //或者考虑使用当前时刻的电流值
//                    String currentBatter = batterValue.toString();
//                    String latestBatter = latestBatterState.get(line.getString(EndTempConstant.dwsField_chargeBegin));
//                    if (ChargeUtil.single().batterDelta(latestBatter,currentBatter)){
//                        //如果变化幅度大，那么选择上一条
//                        i_k = latestBatter;
//                    }else {
//                        i_k = currentBatter;
//                    }
//                    if (StringUtils.isBlank(i_k)){
//                        LogTE.info(String.format("温度预估停止 #&# 电流key=%s #&# 电流field=%s #&# 电流值=%s",batterRedisKey,vinVal,batterState));
//                        break
//                    }
//                }
                if (socValue.compareTo(new BigDecimal(95))>=0 ){
                    //2022-10-10 的方案= 读取厂商提供的默认表，即电池额定容量乘以倍率
                    BigDecimal batterRatio = socMapDefault.batterDefault(socValue.toString(), tmpTemp, bmsCellVoltMin, bmsCellVoltMax);
                    try {
                        iK=capBd.multiply(batterRatio).toString();
                    }catch (Exception e){
                        //batterRatio 可能为空，因为soc大于95时需要考虑电压，如果电压在范围外那么不能获取到倍率，进而得不到电流
//                    e.printStackTrace()
                    }
                }else {
                    //用当前电流，也可能会出行波动的情况，同样会导致误差偏大.电流是直线下降的这种
                    if (batterValue.abs().intValue()>100){
                        iK = batterValue.multiply(new BigDecimal(0.65)).setScale(1,BigDecimal.ROUND_HALF_DOWN).toString();
                    }else {
                        iK = batterValue.toString();
                    }
                }
                if (StringUtils.isBlank(iK)){
                    System.out.println(String.format("预估停止 电流值=null #&# 电流key=%s #&# 电流field=%s #&# 电流值=%s",batterRedisKey,vinVal,batterState));
                    break;
                }
            }else {
                //电流不为空 但是否有效 也要校验下
                BigDecimal ikBd = new BigDecimal(iK);
                if (
                        batterValue.abs().intValue() > ikBd.multiply(new BigDecimal(2)).abs().intValue()
                        || ikBd.abs().intValue() > batterValue.multiply(new BigDecimal(2)).abs().intValue()
                ){
                    //如果当前电流是ik的2倍还多，那么ik就是无效的值
                    iK = batterValue.multiply(new BigDecimal(0.80)).setScale(1,BigDecimal.ROUND_HALF_DOWN).toString();
                }
            }
            //2.2 求S_k
            String axisTempAcc = AxisInfo.singleInstance().axisTempAcc(line,iK,tmpTemp,confMap,false);
//            String axisTempAcc = ChargeUtil.single().axisTempAcc(line,i_k,tmpTemp)
            String tempAccRedisKey = redisNameSpaceTemp.concat(axisTempAcc);
//            String tempAccState = ChargeUtil.single().getRedisHValTemp(jedis, tempAccRedisKey,vinVal)
            String tempAccState = RocksData.obj().getRocksValTemp(mapTempAvgState,tempAccRedisKey,vinVal);
            String sK = JSONObject.parseObject(StringUtils.isBlank(tempAccState)?ChargePredictFields.ins().jsonBlank:tempAccState).getString(ChargePredictFields.ins().tempMoveAvgField);
            if (StringUtils.isBlank(sK)){
                //查找S_K得默认值
                String axisTempAccDefault = ChargeInfo.single().axisTempAccDefault(line, iK, tmpTemp);
                String tempAccRedisKeyDefault = redisNameSpaceTemp.concat(axisTempAccDefault);
//                String tempAccStateAvg = ChargeUtil.single().getRedisHValTemp(jedis, tempAccRedisKeyDefault, "avg")
                String tempAccStateAvg = RocksData.obj().getRocksValTemp(mapTempAvgState,tempAccRedisKeyDefault,"avg");
                String skAvg = JSONObject.parseObject(StringUtils.isBlank(tempAccStateAvg)?ChargePredictFields.ins().jsonBlank:tempAccStateAvg).getString(ChargePredictFields.ins().tempMoveAvgField);
                sK = skAvg;
                if (StringUtils.isBlank(sK)){
                    //温升速率默认值 0.01 人为填的
                    sK = "0.01";
                }
                if (StringUtils.isBlank(sK)){
                    System.out.println(String.format("预估停止 温升速率=null #&# 温升key=%s #&# 温升field=%s #&#  温升速率=%s",tempAccRedisKey,vinVal,tempAccState));
                    break;
                }
            }
            //2.3 求delta_time= (Cap*SOH_k*1%)/I_k
            if (sohValue == null || StringUtils.isBlank(capacity) || StringUtils.isBlank(iK) || StringUtils.isBlank(sK)){
                break;
            }
            if (sohValue>100){sohValue=100;}
            BigDecimal deltaTime = null;
            BigDecimal subtract = socStep;
            int compare = socValue.add(socStep).compareTo(socLimitVal);
            if (compare>=0){
                subtract = socLimitVal.subtract(socValue);
                deltaTime = deltaTime(capacity,sohValue,iK,subtract);
                endFlag=true;
            }else {
                deltaTime = deltaTime(capacity,sohValue,iK,socStep);
            }
            sumDeltaTime = sumDeltaTime.add(deltaTime).setScale(2,BigDecimal.ROUND_DOWN);
            //2.4 计算当前soc的预估温度 T_k'＝T_k+S_k*△t
            BigDecimal intervalTemp = intervalTemp(tmpTemp, sK, deltaTime).setScale(2,BigDecimal.ROUND_DOWN);
            tmpTemp = intervalTemp.toString();
            String s = tmpTemp.concat(ChargePredictFields.ins().char3).concat(sumDeltaTime.toString());
            intervalTempList.add(socValue.add(subtract).toString().concat(ChargePredictFields.ins().char3).concat(s));
            //end 更新socValue
            try {
                socValue = socValue.add(socStep);
            }catch (Exception e){
                socValue = socValue.add(new BigDecimal(10));
            }
            if (endFlag){
                break;
            }
        }
        return intervalTempList;
    }
    /**
     * @description: 间隔点温度计算 T_k'＝T_k+S_k*△t
     * @author:  GW00280745
     * @date: 2022/5/19 13:45
     * @param: tmpTemp
     * @param: s_k
     * @param: deltaTime
     * @return: java.lang.String
     **/
    private BigDecimal intervalTemp(String tmpTemp, String sK, BigDecimal deltaTime) {
        if (StringUtils.isBlank(sK) || deltaTime == null ){

        }
        BigDecimal deltaTemp = new BigDecimal(sK).multiply(deltaTime);
        BigDecimal temp = new BigDecimal(tmpTemp).add(deltaTemp);
        return temp;
    }
    private BigDecimal int100Bd =new BigDecimal(100);
    /**
     * @description: 每变化单位soc所需时间 单位是小时h  deltaTime = (Cap*SOH_k*1%)/I_k
     * @author:  GW00280745
     * @date: 2022/5/19 13:45
     * @param: capacity
     * @param: sohValue
     * @param: i_k
     * @return: java.math.BigDecimal 单位是min
     **/
    private BigDecimal deltaTime(String capacity, Integer sohValue, String iK,BigDecimal socStep) {
        if (StringUtils.isBlank(capacity)){
            capacity = "160";
        }
        if (StringUtils.isBlank(iK)){return null;}
        BigDecimal sohBd = new BigDecimal(sohValue).divide(int100Bd);
        BigDecimal socStepBd = socStep.divide(int100Bd);
        //直接去掉多余的位数 ,例如 -5.90000 得到 -5.90
        BigDecimal ikAbs = new BigDecimal(iK).setScale(2, BigDecimal.ROUND_DOWN).abs();
        BigDecimal time = new BigDecimal(capacity)
                .multiply(sohBd)
                .multiply(socStepBd)
                //在除不尽的时候选择怎样处理 ROUND_HALF_UP=四舍五入
                .divide(ikAbs,BigDecimal.ROUND_HALF_UP)
                .multiply(new BigDecimal(60));
        return time;
    }

    private String parseConf(Map<String, Object> confMap,String confKey,String defaultVal){
        try {
            return confMap.get(confKey).toString();
        }catch (Exception e){
//            e.printStackTrace()
            return defaultVal;
        }
    }
}
